import { ref, markRaw } from 'vue'
import { marked } from 'marked'
import { deepList } from '../json/aidata.js'
import '../../../libs/geolocation.min.js'
import getLocation from './getLocation.js'
export default class ChatMessage {
  constructor() {
    this.messages = ref([])
    this.isWait = ref(false)
    this.waitId = null
    this.currentOpenApi = null
  }
  //提问
  ask() {
    this.abortLastAnswer()
    const askm = new AskMessage()
    this.messages.value.push(askm)
    //当前的请求废弃
    this.currentOpenApi?.abort()
    this.wait()
  }
  //停止上一个回答，如果没有回答结束
  abortLastAnswer() {
    if (this.messages.value.length) {
      let lastMessage = this.messages.value[this.messages.value.length - 1]
      if (lastMessage.type == 'answer') {
        lastMessage.stop()
      }
    }
  }
  //等待，可以修改提问
  //等待跟回答的样式可以一致
  wait() {
    //只会创建一个回答
    if (!this.isWait.value) {
      this.isWait.value = true
      this.am = new AnswerMessage({
        chunks: []
      })
    }
    //每次都创建新请求
    this.currentOpenApi = new OpenAi().query({
      onmessage: (data) => {
        //需要在第一个获取消息的时候添加
        if (this.isWait.value) {
          console.log(data)
          this.messages.value.push(markRaw(this.am))
        }
        if (data.type == 'DONE') {
          this.currentOpenApi.abort()
        }
        this.am.addChunk(data)
        this.isWait.value = false
        //am.addChunk(data)
      }
    })
    //this.waitId = setTimeout(() => {
    //this.isWait.value = false
    //this.answer()
    //}, 3e3)
  }
  getLocation() {
    return getLocation().then(
      (res) => {
        console.log(res)
      },
      (err) => {
        console.log(err)
      }
    )
  }
  testData(am) {
    let i = 0
    let tid = setInterval((res) => {
      am.addChunk(deepList[i])
      i++
      if (i == deepList.length - 1) {
        clearInterval(tid)
      }
    }, 30)
  }
  //回答
  answer() {
    let am = new AnswerMessage({
      chunks: []
    })
    this.messages.value.push(markRaw(am))
    let i = 0
    let tid = setInterval((res) => {
      am.addChunk(deepList[i])
      i++
      if (i == deepList.length - 1) {
        clearInterval(tid)
      }
    }, 0)
  }
}

class OpenAi {
  constructor() {
    this.es = null
    this.isAbort = false
  }
  query(options) {
    const es = new EventSource('http://localhost:3000/')
    es.onmessage = function(event) {
      if (this.isAbort) return
      console.log('Message from server - ', event.data)
      console.log(event.data)
      if (event.data.match(/^{.+}$/)) {
        options.onmessage(JSON.parse(event.data))
      }
    }
    es.onerror = function(err) {
      console.error('EventSource failed:', err)
      es.close()
    }
    this.es = es
    return this
  }
  abort() {
    this.isAbort = true
    this.es?.close()
  }
}
//语音ask，文字ask，点击ask，等等
class AskMessage {
  constructor(options) {
    this.type = 'ask'
    this.text = ref('测试')
  }
}
//文字输出，图片输出，列表输出
class AnswerMessage {
  constructor(options) {
    this.type = 'answer'
    this.options = options
    this.queue = new QueueTask()
    this.chunks = ref([])
    this.lastMessage = null
    //options.chunks.forEach((chunk) => {
    //this.addChunk(chunk)
    //})
  }
  addChunk(chunk) {
    let lastMessage = this.lastMessage
    //如果上一个模块是reasoning，当前模块是不是reasoning，则reasoning结束时间
    if (lastMessage?.type == 'reasoning' && chunk.type != 'reasoning') {
      lastMessage.end()
    }

    //文字模块
    if (chunk.type == 'text') {
      let textM
      if (lastMessage?.type == 'text') {
        textM = lastMessage
      } else {
        textM = new TextMessage()
        this.chunks.value.push(textM)
      }
      this.queue.doSome((next) => {
        return textM.addChunk(chunk, next)
      })
      this.lastMessage = textM
    }
    //简介
    if (chunk.type == 'plain') {
      let plainMessage = new TextMessage()
      this.chunks.value.push(plainMessage)
      this.lastMessage = plainMessage
      this.queue.doSome((next) => {
        plainMessage.addText(chunk.content)
        next()
      })
    }
    //深度思考
    if (chunk.type == 'reasoning') {
      let textM
      if (lastMessage?.type == 'reasoning') {
        textM = lastMessage
      } else {
        textM = new ReasoningMessage()
        this.chunks.value.push(textM)
      }
      this.queue.doSome((next) => {
        return textM.addChunk(chunk, next)
      })
      this.lastMessage = textM
    }

    if (chunk.type == 'getLocation') {
      this.queue.doSome((next) => {
        setTimeout(() => {
          next()
          //getLocation().then(next)
        }, 3e3)
      })
      this.lastMessage = chunk
    }
  }
  //停止回答
  stop() {
    console.log(`停止回答`)
    this.queue.stop()
  }
}

class QueueTask {
  constructor() {
    this.list = [] //任务队列
    this.state = 0 //0空闲 1忙碌
    this.currentTask = null
  }
  doSome(some) {
    this.list.push(some)
    this.next()
  }
  next() {
    if (this.state == 0) {
      this.state = 1
      let fn = this.list.shift()
      if (fn) {
        this.currentTask = fn(() => {
          this.state = 0
          this.next()
        })
      } else {
        this.state = 0
      }
    }
  }
  stop() {
    this.state = 1
    this.currentTask?.pause()
  }
}
class TextMessage {
  constructor(options) {
    this.type = 'text'
    this.text = ''
    this.result = ref('')
  }
  addText(text) {
    this.text += text
    this.result.value = marked.parse(this.text)
  }
  addChunk(chunk, next) {
    let chunkMessage = null
    chunkMessage = new PrintTextMessage({
      text: chunk.content,
      time: 30,
      cb: (charText) => {
        this.addText(charText)
      },
      end: () => next()
    })
    chunkMessage.start()
    return chunkMessage
  }
}
class ReasoningMessage extends TextMessage {
  constructor() {
    super()
    this.type = 'reasoning'
    this.startTime = +new Date()
    this.reasoningTime = ref(0)
  }
  end() {
    this.reasoningTime.value = +new Date() - this.startTime
  }
}
class PrintTextMessage {
  constructor(options) {
    this.options = options
    this.text = options.text
    this.time = options.time
    this.end_cb = options.end
    this.cb = options.cb
    this.index = 0
    this.isPaused = false
    this.isStop = false
    this.timeText = ''
    this.result = ref('')
  }
  start() {
    this.chars = this.text.split('')
    this.print()
  }
  print() {
    this.cb(this.chars[this.index])
    this.index++
    if (this.isPaused) {
    } else {
      if (this.index < this.chars.length) {
        setTimeout(() => {
          this.print()
        }, this.time)
      } else {
        this.isStop = true
        this.end_cb()
      }
    }
  }
  pause() {
    this.isPaused = true
  }
}
